package uy.edu.ort.negocio;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.input.sax.XMLReaders;
import uy.edu.ort.dominio.Cliente;
import uy.edu.ort.dominio.Pagina;
import uy.edu.ort.dominio.Programa;
import uy.edu.ort.excepcionesdb.DBAgregarException;
import uy.edu.ort.excepciones.ProgramaNombreLargoException;

/**
 *
 * @author 153287 - 154559
 */
public class CargaXmlProgramas extends CargaXml {

     private static final Logger LOGGER = Logger.getLogger(CargaXmlProgramas.class.getName());
     
    /**
     * Carta ruta xml
     * @param ruta 
     */
    public CargaXmlProgramas(String ruta) {
        super(ruta);
        persistencia = Persistencia.ObtenerPersistencia();
    }

    /**
     * Parsea xml de programas
     * @return 
     */
    @Override
    public WrapperCargaProgramas parsearXml() {
        List<Programa> programas = new ArrayList<>();
        
        SAXBuilder b = new SAXBuilder(XMLReaders.XSDVALIDATING);
        WrapperCargaProgramas carga = new WrapperCargaProgramas();
        // Creacion documento
        Document doc;
        try {
            doc = b.build(new File(ruta));
        } catch (JDOMException ex) {
            LOGGER.info(ex.getMessage());
            carga.setMessage("ERROR existe un error en el formato de la entrada.");
            return carga;
        } catch (FileNotFoundException ex) {
            LOGGER.info(ex.getMessage());
            carga.setMessage("ERROR: No se encontró el archivo " + ruta);
            return carga;
        } catch (IOException ex) {
            LOGGER.info(ex.getMessage());
            carga.setMessage("ERROR: Desconocido, no se pudo cargar el archivo" + ruta);
            return carga;
        }
        Element element = doc.getRootElement();
        List<Element> elementsPrograma = element.getChildren("programa");
        for (Element elementPrograma : elementsPrograma) {
            try {
                Programa programa = parsearPrograma(elementPrograma);
                programas.add(programa);
            } catch (ProgramaNombreLargoException ex) {
                LOGGER.info(ex.getMessage());
                carga.addErroneo();
            }
        }

       
        for (Programa programaNuevo : programas) {
            try {
                persistencia.guardaPrograma(programaNuevo);
                carga.addExitoso();
                GeneradorDirectorios.generarDirectorio(programaNuevo);
                GeneradorDirectorios.generarArchivosPrograma(programaNuevo);
            } catch (DBAgregarException ex) {
                LOGGER.info(ex.getMessage());
                carga.addDescartado();
            } catch (IOException ex) {
                LOGGER.info(ex.getMessage());
                carga.addDescartado();
            }
        }

        if (carga.getDescartados() > 0 || carga.getErroneos() > 0) {
            carga.setMessage("Se cargó con errores el archivo: " + ruta);
        } else {
            carga.setMessage("Se cargó con éxito el archivo: " + ruta);
        }
        return carga;
    }

    /**
     * Genera programa a partir de nodo xml
     * @param elementPrograma
     * @return
     * @throws ProgramaNombreLargoException 
     */
    private Programa parsearPrograma(Element elementPrograma) throws ProgramaNombreLargoException {
        Programa programa = new Programa();
        Cliente clientePrograma = new Cliente();
        clientePrograma.setIdentificador(elementPrograma.getChild("cliente").getValue());
        programa.setCliente(clientePrograma);
        if (elementPrograma.getChild("nombre").getValue().length() > 255) {
            throw new ProgramaNombreLargoException(null, "Error en nombre de programa demasiado largo.");
        }
        programa.setNombre(elementPrograma.getChild("nombre").getValue());
        Element paginas = elementPrograma.getChild("paginas");
        List<Element> elementsPagina = paginas.getChildren("pagina");
        for (Element elementPagina : elementsPagina) {
            Pagina pagina = parsearPagina(elementPagina);
            pagina.setPrograma(programa);
            programa.getPaginas().add(pagina);
        }
        programa.setCantidadPaginas(programa.getPaginas().size());
        programa.setTamaño(calcularTamañoTotal(programa.getPaginas()));
        return programa;
    }

    /**
     * Genera pagina a partir de nodo xml
     * @param elementPagina
     * @return 
     */
    private static Pagina parsearPagina(Element elementPagina) {
        Pagina pagina = new Pagina();
        pagina.setNombre(elementPagina.getChild("nombre").getValue());
        pagina.setHtmlData(elementPagina.getChild("htmlData").getValue());
        pagina.setTamaño(elementPagina.getChild("htmlData").getValue().getBytes().length);
        return pagina;
    }
    
     /**
     * Retorna el tamaño total del programa.
     * @param listaPaginas
     * @return int
     */
    private static int calcularTamañoTotal(List<Pagina> listaPaginas) {
        int tamaño = 0;
        for (Pagina p : listaPaginas) {
            tamaño += p.getTamaño();
        }
        return tamaño;
    }

}
